package org.itsolutions.javaBackup.logger;

import org.itsolutions.javaBackup.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

/**
 * Common logger using slf4j.
 * @author Tomas Fecko
 */
public final class LoggerHelper implements ILogger {

	/**
	 * 
	 */
	public static final String LOGGER_ARTIFACT_ID = "artifactId";
	/**
	 *
	 */
	private static final long serialVersionUID = -7781999173135923481L;

	private Logger mLogger;

	/**
	 *
	 * @param pLogger logger
	 */
	private LoggerHelper(Logger pLogger) {
		super();
		String artifactID = IOUtils.getProperty(LOGGER_ARTIFACT_ID);
		put("artifactId", (artifactID != null) ? artifactID : "UNKNOWN");
		mLogger = pLogger;
	}

	/**
	 *
	 * @param pClass class or object of class, for which the logger should be returned
	 * @return logger
	 */
	public static ILogger getLogger(Object pClass) {
		ILogger logger = new LoggerHelper(getLoggerSlf4J(pClass));
		return logger;
	}

	// ///////////////////////////////////////////////////////////////////////////////////////
	// //////////////////////////// MESSAGE CREATION /////////////////////////////////////////
	// ///////////////////////////////////////////////////////////////////////////////////////

	/**
	 *
	 * @param pClass class
	 * @return logger
	 */
	@SuppressWarnings("rawtypes")
	private static Logger getLoggerSlf4J(final Object pClass) {
		if (pClass == null) {
			return LoggerFactory.getLogger("No class defined");
		} else if (pClass instanceof Class) {
			return LoggerFactory.getLogger((Class) pClass);
		} else {
			return LoggerFactory.getLogger(pClass.getClass());
		}
	}

	@Override
	public boolean isEnabledFor(ELogLevel pLogLevel) {
		switch (pLogLevel) {
		case TRACE:
			return mLogger.isTraceEnabled();
		case DEBUG:
			return mLogger.isDebugEnabled();
		case INFO:
			return mLogger.isInfoEnabled();
		case WARN:
			return mLogger.isWarnEnabled();
		case ERROR:
			return mLogger.isErrorEnabled();
		default:
			return false;
		}
	}

	private void logSlf4j(ELogLevel pLevel, String pString) {
		switch (pLevel) {
		case TRACE:
			mLogger.trace(pString);
			break;
		case DEBUG:
			mLogger.debug(pString);
			break;
		case INFO:
			mLogger.info(pString);
			break;
		case WARN:
			mLogger.warn(pString);
			break;
		default:
			mLogger.error(pString);
			break;
		}
	}

	private void logSlf4j(ELogLevel pLevel, String pString, Throwable pThrowable) {
		switch (pLevel) {
		case TRACE:
			mLogger.trace(pString, pThrowable);
			break;
		case DEBUG:
			mLogger.debug(pString, pThrowable);
			break;
		case INFO:
			mLogger.info(pString, pThrowable);
			break;
		case WARN:
			mLogger.warn(pString, pThrowable);
			break;
		default:
			mLogger.error(pString, pThrowable);
			break;
		}
	}

	@Override
	public String get(String pKey) {
		return MDC.get(pKey);
	}

	// ////////////////////////////////////////////////////////////////////////////////////////////////////
	// /////////////////////////////////////////// HELPER METHODS /////////////////////////////////////////
	// ////////////////////////////////////////////////////////////////////////////////////////////////////

	@Override
	public void log(ELogLevel pLevel, Object... pMessageParts) {
		if (isEnabledFor(pLevel)) {
			logSlf4j(pLevel, createMessage(pMessageParts));
		}
	}

	@Override
	public void log(ELogLevel pLevel, Throwable pThrowable) {
		if (isEnabledFor(pLevel)) {
			logSlf4j(pLevel, "", pThrowable);
		}
	}

	@Override
	public void log(ELogLevel pLevel, Throwable pThrowable, Object... pMessageParts) {
		if (isEnabledFor(pLevel)) {
			logSlf4j(pLevel, createMessage(pMessageParts), pThrowable);
		}
	}

	private String createMessage(Object... pMessageParts) {
		StringBuilder builder = new StringBuilder();
		for (Object o : pMessageParts) {
			builder.append(o);
		}
		return builder.toString();
	}

	@Override
	public String peek() {
		// log(ELevel.FATAL, "--- PEEK ----------------- ", NDC.peek(), " -------------------------");
		return NDC.peek();
	}

	@Override
	public String pop() {
		// log(ELevel.FATAL, "--- POP ----------------- ", NDC.pop(), " -------------------------");
		String message = NDC.pop();
		return message;
	}

	@Override
	public void push(String pMessage) {
		if (pMessage != null && !pMessage.isEmpty()) {
			// log(ELevel.FATAL, "--- PUSH ----------------- ", pMessage, " -------------------------");
			NDC.push(pMessage);
		}
	}

	@Override
	public void put(String pKey, String pValue) {
		MDC.put(pKey, pValue);
	}

	@Override
	public void remove(String pKey) {
		MDC.remove(pKey);
	}
}
